#include "CachePartitioning.h"
#include <iostream>


void CachePartitioning::calculate_partitioning(int time){
	map<LUNID, LunTotalStatistics*>* luns = view->getMy_luns();
	map<LUNID, LunTotalStatistics*>::iterator LunStatIterator;
	map<int,LunTimeStatistics*>::iterator timeIter;
	total_read_miss = 0;
	list<LunTimeStatistics*> time_stats;
	partition_read_miss = new int [view->getCache()->nof_partitions];

	for(LunStatIterator = luns->begin(); LunStatIterator != luns->end(); LunStatIterator++){
		timeIter = LunStatIterator->second->getAllLunTimeStatistics()->begin();
		while(timeIter != LunStatIterator->second->getAllLunTimeStatistics()->end()){
			if ((*timeIter).first == time){
				partition_read_miss[findPartition((*timeIter).second->lun_id)] += ((*timeIter).second->getStatistic(rand_rm));
				time_stats.push_back((*timeIter).second);
				total_read_miss += ((*timeIter).second->getStatistic(rand_rm));
				break;
			}
			timeIter++;
		}
	}
	calculations(time_stats);
}

void CachePartitioning::calculations(list<LunTimeStatistics*> time_stats){
	map<LUNID, LunTotalStatistics*>* luns = view->getMy_luns();
	double old_c, new_c, factor, new_hits, new_misses;
	int index, hits, misses;
	list<LunTimeStatistics*>::iterator LunStatIterator;

	for(LunStatIterator = time_stats.begin(); LunStatIterator != time_stats.end(); LunStatIterator++){
		hits = (*LunStatIterator)->getStatistic(rand_rh);
		misses = ((*LunStatIterator)->getStatistic(rand_rm));
		index = findPartition((*LunStatIterator)->lun_id);
		old_c = ((misses / total_read_miss) * (view->getCache()->cache_size));
		new_c = ((misses / partition_read_miss[index]) * view->getCache()->partition_sizes[index]);
		factor = 50*log(new_c/old_c);
		new_hits = hits + (factor/100)*hits;
		new_misses = misses - (factor/100)*hits;

		if (new_misses < 0){
			new_misses = 0;
			new_hits = hits + misses;			// check this -> should it be 100?
		}
		if (new_hits < 0 ){						// check this -> the e-mail says if hits < 0, hits = 0, misses = 100%
			new_hits = 0; 
			new_misses = 100;
		}

		(*LunStatIterator)->setNewHits(new_hits);
		(*LunStatIterator)->setNewMisses(new_misses);
	}
}


int CachePartitioning::findPartition(int lunID){
	Cache* cache = view->getCache();

	for(int i = 0; i < cache->nof_partitions; i++){
		for (int j = 0; j < sizeof(cache->partition_luns[i]); j++){
			if (cache->partition_luns[i][j] == lunID) {
				return i;
			}
		}
	}

	cout << "ERROR: could not find lun partition" << endl;
	return -1;

}